﻿Imports System.Reflection, System.Windows.Forms, EnvDTE, EnvDTE80, Microsoft.VisualStudio.Shell
'using Microsoft.VisualStudio.Package;

<Obsolete("Fuck it Man O.o!!", True)>
Friend Class MainController
    Public Property Package As Package
    Public Property DTE As DTE2
    Public Property ContinousContextUpdateIsRunning As Boolean

    '<Obsolete("Use the New Mod_Utilities.CurrentType", True)>
    'Public Property CurrentType As Type

    '<Obsolete("Death", True)>
    'Public Property ViewController As ViewController
    '<Obsolete("Use the New Mod_Utilities.IsConnected", True)>
    'Private Property IsConnected As Boolean
    '<Obsolete("Use Mod_Utilities.IsDebuggerConnected", True)>
    'Public Property IsDebuggerConnected As Boolean
    '<Obsolete("Use Mod_Utilities.LastStackFunction", True)>
    'Public Property LastStackFunction As String


    '<Obsolete("Use the New Mod_Utilities.LocalReachableMembers", True)>
    'Public ReadOnly Property LocalReachableMembers() As IList(Of LocalMember)
    '    Get
    '        Throw New ApplicationException("Exception Occured")
    '        'Dim localFields = From e In DTE.Debugger.CurrentStackFrame.Locals.Cast(Of Expression)()
    '        '                  Where Not e.Name.StartsWith("___")
    '        '                  Select New LocalMember() With {.Name = e.Name, .TypeName = e.Type, .Member = MemberType.Field}

    '        'Dim publicInstanceProperties = From e In CurrentType.GetProperties()
    '        '                               Select New LocalMember() With {.Name = e.Name, .Type = e.PropertyType, .TypeName = e.PropertyType.FullName,
    '        '                                                              .Member = MemberType.[Property], .HasGetAccessor = e.CanRead, .HasSetAccessor = e.CanWrite}

    '        'Dim publicStaticProperties = From e In CurrentType.GetProperties(BindingFlags.[Static])
    '        '                             Select New LocalMember() With {.Name = e.Name, .Type = e.PropertyType, .TypeName = e.PropertyType.FullName,
    '        '                                                            .Member = MemberType.[Property], .HasGetAccessor = e.CanRead, .HasSetAccessor = e.CanWrite}


    '        'Dim nonPublicInstanceProperties = From e In CurrentType.GetProperties(BindingFlags.Instance Or BindingFlags.NonPublic)
    '        '                                  Select New LocalMember() With {.Name = e.Name, .Type = e.PropertyType, .TypeName = e.PropertyType.FullName,
    '        '                                                                 .Member = MemberType.[Property], .HasGetAccessor = e.CanRead, .HasSetAccessor = e.CanWrite}


    '        'Dim nonPublicStaticProperties = From e In CurrentType.GetProperties(BindingFlags.[Static] Or BindingFlags.NonPublic)
    '        '                                Select New LocalMember() With {.Name = e.Name, .Type = e.PropertyType, .TypeName = e.PropertyType.FullName,
    '        '                                                               .Member = MemberType.[Property], .HasGetAccessor = e.CanRead, .HasSetAccessor = e.CanWrite}

    '        'Dim reachableMembers = localFields.Union(publicInstanceProperties).Union(publicStaticProperties).Union(nonPublicInstanceProperties).Union(nonPublicStaticProperties).OrderBy(Function(a) a.Name)
    '        'Dim result As List(Of LocalMember) = Nothing
    '        'For i As Integer = 0 To 9
    '        '    Try
    '        '        result = reachableMembers.ToList()
    '        '    Catch
    '        '        System.Threading.Thread.Sleep(50)
    '        '    End Try
    '        'Next
    '        'Return result
    '    End Get
    'End Property




    '#Region "       Utilities     >>>"
    '    <Obsolete("Use the New Mod_Utilities.Log", True)>
    '    Private Sub Log(ByVal txt As String)
    '        System.Diagnostics.Debug.WriteLine(txt)
    '    End Sub


    '    <Obsolete("Use the New Mod_Utilities.CurrentDomain_AssemblyResolve", True)>
    '    Private Function CurrentDomain_AssemblyResolve(ByVal sender As Object, ByVal args As ResolveEventArgs) As Assembly
    '        If args.Name = GetCurrentType.Assembly.FullName Then
    '            Return GetCurrentType.Assembly
    '        Else
    '            Return Nothing
    '        End If
    '    End Function

    '    <Obsolete("Replaced By Mod_Utilities.injector_Results", True)>
    '    Private Sub injector_Results(ByVal sender As Object, ByVal e As Injector.ResultEventArgs)
    '        If e.CompilingFailed Then
    '            'Me.ViewController.TellExecutionFailed(e.ErrorMessage)
    '            Mod_Utilities.ToolWindowControl_Only.TellExecutionFailed(e.ErrorMessage)
    '        Else
    '            'Me.ViewController.DisplayResultExpression(e.ResultExpression)
    '            Mod_Utilities.ToolWindowControl_Only.DisplayResultExpression(e.Result)
    '        End If
    '    End Sub

    '    'Private Sub ViewController_QueryContextType(ByVal sender As Object, ByVal e As ToolWindowControl.QueryContextTypeEventArgs)
    '    '    If DTE.Debugger.CurrentMode <> dbgDebugMode.dbgBreakMode Then
    '    '        Return
    '    '    End If

    '    '    e.ContextType = GetContextType()
    '    'End Sub


    '#End Region





    'Public Sub New(ByVal toolWindow As VsToolWindow, ByVal dte2 As DTE2, ByVal package__1 As Package)


    Public Sub New()
        Mod_Utilities.IsConnected = False
        StartContinousContextUpdate()
    End Sub


    '<Obsolete("Death", True)>
    'Public Sub Connect()
    '    If Mod_Utilities.IsConnected Then
    '        Return
    '    End If
    '    ViewController.Connect()
    '    Mod_Utilities.IsConnected = True
    'End Sub





    'Private Sub ViewController_QueryConnect(ByVal sender As Object, ByVal e As EventArgs)
    '    Try
    '        UpdateContextTypeIfChanged()
    '        IsDebuggerConnected = True
    '    Catch exc As Exception
    '        MessageBox.Show("Konnte nicht verbinden: " & exc.Message & " " & exc.StackTrace)
    '    End Try
    'End Sub


    'Aaron
    'Private Sub TryConnectToDebugger()
    '    Try
    '        UpdateContextTypeIfChanged()
    '        IsDebuggerConnected = True
    '    Catch exc As Exception
    '        Log("Konnte nicht verbinden: " & exc.Message & " " & exc.StackTrace)
    '    End Try
    'End Sub





    Private Sub StartContinousContextUpdate()
        Dim updateAction As Action =
            Sub()
                While ContinousContextUpdateIsRunning

                    'TryConnectToDebugger()

                    'Aaron
                    Try
                        UpdateContextTypeIfChanged()
                        Mod_Utilities.IsDebuggerConnected = True
                    Catch exc As Exception
                        Mod_Utilities.Log("Konnte nicht verbinden: " & exc.Message & " " & exc.StackTrace)
                    End Try
                    'Aaron

                    System.Threading.Thread.Sleep(10000)
                End While
            End Sub
        ContinousContextUpdateIsRunning = True
        updateAction.BeginInvoke(Nothing, Nothing)
    End Sub

    Private Sub UpdateContextTypeIfChanged()
        If Mod_Utilities.IsConnected AndAlso DTE.Debugger.CurrentMode = dbgDebugMode.dbgBreakMode Then
            Dim currentFunction As String = DTE.Debugger.CurrentStackFrame.FunctionName

            Mod_Utilities.Log("ExtendedImmediateAddInn - Connect")
            Mod_Utilities.Log("Current Func: " & currentFunction)

            If currentFunction <> Mod_Utilities.LastStackFunction Then
                Mod_Utilities.Log("-> not cached already, have to analyze " & currentFunction)


                'Mod_Utilities.CurrentType = DTE.Debugger.GetCurrentType()


                Mod_Utilities.Log("CurrentType: " & Mod_Utilities.CurrentType.ToString())
                Dim context = GetContextType()
                Mod_Utilities.Log("ContextType (compiled in background): " & context.ToString())
                AddHandler AppDomain.CurrentDomain.AssemblyResolve, New ResolveEventHandler(AddressOf Mod_Utilities.CurrentDomain_AssemblyResolve)
                Mod_Utilities.ToolWindowControl_Only.SetContextType(context)

                RemoveHandler AppDomain.CurrentDomain.AssemblyResolve, New ResolveEventHandler(AddressOf Mod_Utilities.CurrentDomain_AssemblyResolve)
                Mod_Utilities.LastStackFunction = currentFunction
                Mod_Utilities.Log("Done.")
            End If
        End If
    End Sub


    'Private Sub ViewController_RunIntrudingMethod(ByVal sender As Object, ByVal e As ToolWindowControl.RunIntrudingMethodEventArgs)
    '    If DTE.Debugger.CurrentMode <> dbgDebugMode.dbgBreakMode Then
    '        MessageBox.Show("You have to be inside a debugging session to inject intruding methods", "Not Possible", MessageBoxButtons.OK, MessageBoxIcon.Information)
    '        Return
    '    End If

    '    Execute(e.Source)
    'End Sub





    Private Function GetContextType() As Type
        'Mod_Utilities.CurrentType = DTE.Debugger.GetCurrentType()

        Dim resolver = DTE.Debugger.GetResolver()

        'Aaron Commened out
        'resolver.VsApplication = DTE



        resolver.ReferencedAssemblies.ToList()

        Dim compiler As New Compiler("", resolver.ReferencedAssemblies, Mod_Utilities.LocalReachableMembers.ToList(), LocalsMode.PrivateClassFields)
        compiler.Compile()

        Return compiler.InjectorType
    End Function



    Private Sub Execute(ByVal source As String)
        Dim refAssemblies = DTE.Debugger.GetResolver().ReferencedAssemblies
        Dim localMembers = Mod_Utilities.LocalReachableMembers.ToList()

        Dim injector As New Injector(DTE.Debugger, refAssemblies, localMembers) 'source, 


        'AddHandler injector.Results, New EventHandler(Of Injector.ResultEventArgs)(AddressOf Mod_Utilities.injector_Results)



        'injector.Results += New EventHandler(Of Injector.ResultEventArgs)(AddressOf injector_Results)
        injector.Execute()
    End Sub








End Class